#include "ast.h"
#include <cstdio>
#include <iostream>
using namespace std;

// ENum
void ENum::print() const {
    printf("ENum %d", value);
}

// EId
void EId::print() const {
    printf("EId %s", id.c_str());
}

// EUnOp
void EUnOp::print() const {
    printf("EUnOp (%s, ", stringOfUnOp(op).c_str());
    expr->print();
    printf(")");
}

// EBinOp
void EBinOp::print() const {
    printf("EBinOp (%s, ", stringOfBinOp(op).c_str());
    left->print();
    printf(", ");
    right->print();
    printf(")");
}

// ECall
ECall::ECall(const string& s, vector<Expr*> a) : id(s) {
    for (auto& e : a) args.emplace_back(e);
}

void ECall::print() const {
    printf("ECall (%s, [", id.c_str());
    for (const auto& arg : args) {
        arg->print();
        printf("; ");
    }
    printf("])");
}

// SBlock
SBlock::SBlock(vector<Stmt*> s) {
    for (auto& stmt : s) stmts.emplace_back(stmt);
}

void SBlock::print() const {
    printf("SBlock [\n");
    for (const auto& stmt : stmts) stmt->print();
    printf("]\n");
}

int SBlock::countLocalVars() const {
    int count = 0;
    for (const auto& stmt : stmts) {
        count += stmt->countLocalVars();
    }
    return count;
}

// SIf
SIf::SIf(Expr* c, Stmt* t, Stmt* e) : cond(c), thenStmt(t), elseStmt(e) {}

void SIf::print() const {
    printf("SIf (");
    cond->print();
    printf(", ");
    thenStmt->print();
    if (elseStmt) {
        printf(", ");
        elseStmt->print();
    }
    printf(")\n");
}

int SIf::countLocalVars() const {
    int count = thenStmt->countLocalVars();
    if (elseStmt) count += elseStmt->countLocalVars();
    return count;
}

// SWhile
void SWhile::print() const {
    printf("SWhile (");
    cond->print();
    printf(", ");
    body->print();
    printf(")\n");
}

int SWhile::countLocalVars() const {
    return body->countLocalVars();
}

// SReturn
void SReturn::print() const {
    printf("SReturn (");
    if (expr) expr->print();
    else printf("None");
    printf(")\n");
}

int SReturn::countLocalVars() const { return 0; }

// SBreak
void SBreak::print() const { printf("SBreak\n"); }
int SBreak::countLocalVars() const { return 0; }

// SContinue
void SContinue::print() const { printf("SContinue\n"); }
int SContinue::countLocalVars() const { return 0; }

// SDecl
void SDecl::print() const {
    printf("SDecl (%s, ", id.c_str());
    expr->print();
    printf(")\n");
}

int SDecl::countLocalVars() const { return 1; }

// SAssign
void SAssign::print() const {
    printf("SAssign (%s, ", id.c_str());
    expr->print();
    printf(")\n");
}

int SAssign::countLocalVars() const { return 0; }

// FuncDef
void FuncDef::print() const {
    printf("FuncDef (%s, [", name.c_str());
    for (const auto& p : params) {
        printf("%s; ", p->id.c_str());
    }
    printf("],\n");
    body->print();
    printf(")\n");
}

// CompUnit
CompUnit::CompUnit(vector<FuncDef*> f) {
    for (auto& func : f) funcs.emplace_back(func);
}

void CompUnit::print() const {
    printf("CompUnit [\n");
    for (const auto& func : funcs) func->print();
    printf("]\n");
}

// 一元运算符转字符串
string stringOfUnOp(UnOp op) {
    switch(op) {
        case UnOp::Not: return "Not";
        case UnOp::Neg: return "Neg";
        default: return "Unknown";
    }
}

//二元运算符转字符串
string stringOfBinOp(BinOp op) {
    switch(op) {
        case BinOp::Add: return "Add";
        case BinOp::Sub: return "Sub";
        case BinOp::Mul: return "Mul";
        case BinOp::Div: return "Div";
        case BinOp::Mod: return "Mod";
        case BinOp::Eq: return "Eq";
        case BinOp::Neq: return "Neq";
        case BinOp::Lt: return "Lt";
        case BinOp::Le: return "Le";
        case BinOp::Gt: return "Gt";
        case BinOp::Ge: return "Ge";
        case BinOp::And: return "And";
        case BinOp::Or: return "Or";
        default: return "Unknown";
    }
}

//表达式打印
void printExprOption(const unique_ptr<Expr>& expr) {
    if (expr) expr->print();
    else printf("None");
}

void SExpr::print() const {
    printf("SExpr (");
    expr->print();
    printf(")\n");
}

int SExpr::countLocalVars() const { 
    return 0; 
}